(function(){
	var order={};
	order.setting={
		defaultMultiple: 50,
		maxMultiple: 999
	}
	// 定义彩种ID常量
	order.LOTTERYID={
		SPORTTERY: 46,
		UNIONLOTTO: 1
	};
	order.PLAYTYPEID={
		SPF: 354,	//胜平负
		RQSPF: 269,	//让球胜平负
		JQS: 270,	//进球数
		BF: 271,	//比分
		BQC: 272	//半全场
	};
	order.SELECTION={
		HOMEWIN: 3,
		DRAW: 1,
		AWAYWIN: 0
	};
	order.orderObject={
		lottery_id: order.LOTTERYID.SPORTTERY,
		content: "",
		draw: "",
		group_type: "",
		_content_obj: [],
		_draw_obj:[],
		_group_type_obj:[],
		_selection_catesian_product:null,
		multiple: order.setting.defaultMultiple,
		amount: null,
		bet_num: null,
		max_prize: null,
		min_prize: null
	};
	// 基础工具方法
	// 克隆对象
	var cloneObject=function(source,isFilterPrivateProperty){
		const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
		for(var keys in source){ // 遍历目标
			if(isFilterPrivateProperty&&keys.substr(0,1)=='_')continue;
			if(source.hasOwnProperty(keys)){
				if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象，就递归一下
					targetObj[keys] = source[keys].constructor === Array ? [] : {};
					targetObj[keys] = cloneObject(source[keys],isFilterPrivateProperty);
				}else{ // 如果不是，就直接赋值
					targetObj[keys] = source[keys];
				}
			}
		}
		return targetObj;
	};
	/**
	* 计算笛卡尔积
	* cartesianProductOf([['a','b'],['1','2'],['I','II','III']]);
	* 返回：
	* Array(12):
	* 	0: (3) ["a", "1", "I"]
	*	1: (3) ["a", "1", "II"]
	*	2: (3) ["a", "1", "III"]
	*	3: (3) ["a", "2", "I"]
	*	4: (3) ["a", "2", "II"]
	*	5: (3) ["a", "2", "III"]
	*	6: (3) ["b", "1", "I"]
	*	7: (3) ["b", "1", "II"]
	*	8: (3) ["b", "1", "III"]
	*	9: (3) ["b", "2", "I"]
	*	10: (3) ["b", "2", "II"]
	*	11: (3) ["b", "2", "III"]
	*/
	var cartesianProductOf=function(arrays){
	    return Array.prototype.reduce.call(arrays, function (a, b) {
	        var ret = [];
	        a.forEach(function (a) {
	            b.forEach(function (b) {
	                ret.push(a.concat([b]));
	            });
	        });
	        return ret;
	    }, [[]]);
	}
	/*
		组合主要用到了循环加递归的方式 实现的，个人觉得很是精辟，
		举例来说吧choose([1,2,3,4,5,6], 3)
		第一次循环的时候 arr是[1,2,3,4,5,6],size=3,result=[],
		经过一次递归后的结果是什么样的了?递归里面也有循环递归
		经过第一次循环第一次递归变为arr=[3,4,5,6],size=1,result=[1,2],所以结果就出来了[1,2,3][1,2,4][1,2,5][1,2,6]
		那么第一次循环第二次递归arr=[4,5,6],size=1,result=[1,3],所以结果就出来了[1,3,4][1,3,5][1,3,6]
		那么第一次循环第三次递归arr=[5,6],size=1,result=[1,4],所以结果就出来了[1,4,5][1,4,6]
		那么第一次循环第四次递归arr=[6],size=1,result=[1,5],所以结果就出来了[1,5,6]
		那么第二次循环第一次递归变为arr=[4,5,6],size=1,result=[2,3],所以结果就出来了[2,3,4][2,3,5][2,3,6]
	*/
    function combination(arr, size) {
        var allResult = [];
        (function (arr, size, result) {
            var arrLen = arr.length;
            if (size > arrLen) {
                return;
            }
            if (size == arrLen) {
                allResult.push([].concat(result, arr))
            } else {
                for (var i = 0 ; i < arrLen; i++) {
                    var newResult = [].concat(result);
                    newResult.push(arr[i]);

                    if (size == 1) {
                        allResult.push(newResult);
                    } else {
                        var newArr = [].concat(arr);
                        newArr.splice(0, i + 1);
                        arguments.callee(newArr, size - 1, newResult);
                    }
                }
            }
        })(arr, size, []);
        return allResult;
    }
	// 私有方法
	/**
	* 传入一个matchItem，如果订单结构当中已经有，则返回key，若没有则创建一个再返回key
	* 
	*/
	var _getOrCreateMatchItem=function(matchItem){
		var key=null;
		for(var index in order.orderObject._content_obj){
			if(matchItem.matchid==order.orderObject._content_obj[index].matchid){
				key = index;
			}
		}
		if(key===null){
			order.orderObject._content_obj.push(matchItem);
			key = order.orderObject._content_obj.length-1;
		}
		return order.orderObject._content_obj[key];
	};
	var _setBetContentItem=function(betContentItem){
		var key=null;
		for(var index in this.betContent){
			if(betContentItem.playtypeid==this.betContent[index].playtypeid && betContentItem.selection==this.betContent[index].selection){
				this.betContent[index].odds=betContentItem.odds;
				key=index;
			}
		}
		if(key===null){
			this.betContent.push(betContentItem);
			key=this.betContent.length-1;
		}
		return key;
	}
	var _setDraw=function(draw){
		var key=null;
		for(var i in order.orderObject._draw_obj){
			if(draw==order.orderObject._draw_obj[i]){
				key=i;
			}
		}
		if(key===null){
			order.orderObject._draw_obj.push(draw);
			key=order.orderObject._draw_obj.length-1;
		}
		return key;
	}
	var _clearDrawList=function(){
		order.orderObject._draw_obj=[];
	}
	// 生成期号列表
	var _generalDrawList=function(){
		_clearDrawList();
		for(var i in order.orderObject._content_obj){
			_setDraw(order.orderObject._content_obj[i].draw);
		}
	}
	var _setDefaultParlay=function(){
		if(order.orderObject._group_type_obj.length>0)return;
		var countOfMatch=order.getCountOfMatch();
		var numberOfParlay=countOfMatch>8 ? 8 : countOfMatch;
		var parlay=numberOfParlay+'001';
		// order.orderObject._group_type_obj=[parlay];
		order.addParlayType(parlay);
	}
	// 传一个目标对象，返回去除所有私有变量后的对象
	var _getClearObject=function(objSource){
		var tempOrder=cloneObject(objSource,true);
		// 去掉所有私有属性后再保存
		// for(var key in tempOrder){
		// 	if(key.substr(0,1)=='_')delete tempOrder[key];
		// }
		// delete tempOrder._content_obj;
		// delete tempOrder._draw_obj;
		// delete tempOrder._group_type_obj;
		// delete tempOrder._selection_catesian_product;
		return tempOrder;
	}
	var _deleteOrderInLocalStorage=function(){
		window.localStorage.removeItem('order');
	}
	var _saveOrderToLocalStorage=function(){
		_generalStringProperty();
		var tempOrder=_getClearObject(order.orderObject);
		window.localStorage.setItem('order',JSON.stringify(tempOrder));
	}
	var _loadOrderFromLocalStorage=function(){
		var tempOrder=JSON.parse(window.localStorage.getItem('order'));
		if(!tempOrder)return;
		// 还原数据到_content_obj、_group_type_obj、_draw_obj，只要用choose循环处理_content_obj里面的betContent，保存就可以得到_draw_obj
		// 先恢复过关方式
		order.orderObject._group_type_obj=tempOrder.group_type.split(';');
		// 恢复倍数设置
		order.orderObject.multiple=tempOrder.multiple;
		// 需要用choose方法遍历构建，不能直接恢复
		tempOrder._content_obj=JSON.parse(tempOrder.content);
		//清空容器
		order._content_obj=[];
		//遍历读取
		for(var matchItemIndex in tempOrder._content_obj){
			for(var betContentItemIndex in tempOrder._content_obj[matchItemIndex].betContent){
				// 要先处理一下playtype，页面上用的是had、hhad代表非让球和让球，在这里把数据接口里的标准格式转换成此种表示方式
				var playtype=null;
				switch(tempOrder._content_obj[matchItemIndex].betContent[betContentItemIndex].playtypeid){
					case order.PLAYTYPEID.SPF:
						playtype='had';break;
					case order.PLAYTYPEID.RQSPF:
						playtype='hhad';break;
					default:
				}
				// 再处理一下selection，页面上使用homewin/draw/awaywin来表示胜平负选项，在这里把数据接口里的标准格式转换成此种表示方式
				var selectionName=null;
				switch(tempOrder._content_obj[matchItemIndex].betContent[betContentItemIndex].selection){
					case order.SELECTION.HOMEWIN:
						selectionName='homewin';break;
					case order.SELECTION.DRAW:
						selectionName='draw';break;
					case order.SELECTION.AWAYWIN:
						selectionName='awaywin';break;
					default:
				}
				// 执行choose操作
				order.choose(
					tempOrder._content_obj[matchItemIndex].matchid,
					tempOrder._content_obj[matchItemIndex].matchtime,
					tempOrder._content_obj[matchItemIndex].matchkey,
					tempOrder._content_obj[matchItemIndex].draw,
					tempOrder._content_obj[matchItemIndex].handicap,
					playtype,
					selectionName,
					tempOrder._content_obj[matchItemIndex].betContent[betContentItemIndex].odds
				);
			}
		}
		// 全部遍历choose完成之后_saveOrder保存一下
		_generalBasicData();
	}
	var _generalCartesianProductOfSelection=function(){
		// 这个是全部选项的矩阵
		var selectionMatrix=[];
		for(var i in order.orderObject._content_obj){
			selectionMatrix.push(order.orderObject._content_obj[i].betContent);
		}
		// 这个是按过关方式构造的选项矩阵列表
		var listOfSelectionByParlay=[];
		// 遍历全部过关方式，构造各个过关方式的选项列表
		for(var i in order.orderObject._group_type_obj){
			// 只支持普通过关，不支持混合过关
			if(order.orderObject._group_type_obj[i].substr(-3)=='001'){
				// 取出过关数
				var countOfParlay=parseInt(order.orderObject._group_type_obj[i].substr(0,1));
				// 用排列算法按过关数构造选项列表
				var result=combination(selectionMatrix,countOfParlay);
				// 将构造出来的选项列表并入总列表中
				listOfSelectionByParlay=listOfSelectionByParlay.concat(result);
			}
		}
		// 这个是遍历所有过关方式构成的笛卡尔积
		var cartesianProductResult=[];
		for(var i in listOfSelectionByParlay){
			cartesianProductResult=cartesianProductResult.concat(cartesianProductOf(listOfSelectionByParlay[i]));
		}
		//把笛卡尔积写入orderObject
		order.orderObject._selection_catesian_product=cartesianProductResult;
	};
	var _calculateCountOfLines=function(){
		if(order.orderObject._selection_catesian_product===null)_generalCartesianProductOfSelection();
		order.orderObject.bet_num=order.orderObject._selection_catesian_product.length
		order.orderObject.amount=order.orderObject.bet_num*order.getMultiple()*2;
		return order.orderObject.bet_num;
	}
	// 生成字符串属性
	var _generalStringProperty=function(){
		// 取得清洁的BetContent存储到content字符串变量当中
		var clearBetContentObj=_getClearObject(order.orderObject._content_obj);
		order.orderObject.content=JSON.stringify(clearBetContentObj);
		// 生成过关方式的字符串变量
		order.orderObject.group_type=order.orderObject._group_type_obj.join(';');
		// 生成期号列表的字符串变量
		order.orderObject.draw=order.orderObject._draw_obj.join(';');
	}
	// 生成期号、选项笛卡尔积、计算注数、计算奖金范围等基础数据
	// 每一次增删选项都会执行此方法生成最新的基础数据
	var _generalBasicData=function(){
		//计算奖金、注数等
		//写入localstorage
		// _setDefaultParlay(); // 这里不能在save里生成默认过关方式，否则可能会覆盖已经设置的过关方式 --也未必，只要过关方式不为空时生成就好了。
		_generalDrawList();
		_generalCartesianProductOfSelection();
		_calculateCountOfLines();
		_calculatePrizeRange();

		console.log(order.orderObject);
	}
	/**
	* 生成某个玩法的选项的比分矩阵
	* 胜平负：_generalScoreMatrix(order.PLAYTYPEID.SPF,{ selection: order.SELECTION.HOMEWIN });
	* 让球胜平负：_generalScoreMatrix(order.PLAYTYPEID.RQSPF,{ selection: order.SELECTION.HOMEWIN, handicap: '2' });
	*/
	var _generalScoreMatrix=function(playtypeid,propertyOfPlayType){
		var defaultPropertyOfPlayType={
			selection: null,
			handicap: null
		};
		var matrix=[
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false],
			[false,false,false,false,false,false,false]
		];
		switch(playtypeid){
			case order.PLAYTYPEID.SPF:
				if(propertyOfPlayType.selection==order.SELECTION.HOMEWIN){
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h>a)matrix[h][a]=true;
						}
					}
				}
				else if(propertyOfPlayType.selection==order.SELECTION.DRAW){
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h==a)matrix[h][a]=true;
						}
					}
				}
				else{
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h<a)matrix[h][a]=true;
						}
					}
				}
				break;
			case order.PLAYTYPEID.RQSPF:
				var handicap=parseFloat(propertyOfPlayType.handicap);
				if(propertyOfPlayType.selection==order.SELECTION.HOMEWIN){
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h+handicap>a)matrix[h][a]=true;
						}
					}
				}
				else if(propertyOfPlayType.selection==order.SELECTION.DRAW){
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h+handicap==a)matrix[h][a]=true;
						}
					}
				}
				else{
					for(var h=0;h<7;h++){
						for(var a=0;a<7;a++){
							if(h+handicap<a)matrix[h][a]=true;
						}
					}
				}
				break;
			case order.PLAYTYPEID.JQS:
				// 暂未支持
				// break;
			case order.PLAYTYPEID.BF:
				// 暂未支持
				// break;
			case order.PLAYTYPEID.BQC:
				// 暂未支持
				// break;
			default:
				return false;
		}
		return matrix;
	}
	/**
	* 求两个矩阵的 AND（并集）
	* 用于判断两个玩法的选项是否互斥，若并集为零矩阵即为互斥，否则不互斥
	*
	*/
	var _matrixAND=function(matrixA,matrixB){
		var matrixResult=[];
		if(matrixA.length!=matrixB.length)return false;
		for(var h=0;h<matrixA.length;h++){
			if(matrixA[h].length!=matrixB[h].length)return false;
			matrixResult[h]=[];
			for(var a=0;a<matrixA[h].length;a++){
				matrixResult[h][a]=matrixA[h][a]&&matrixB[h][a];
			}
		}
		return matrixResult;
	}
	/**
	* 判断一个矩阵是否为零矩阵（所有元素为0的矩阵）
	*
	*
	*/
	var _isZeroMatrix=function(matrix){
		for(var h=0;h<matrix.length;h++){
			for(var a=0;a<matrix[h].length;a++){
				if(matrix[h][a])return false;
			}
		}
		return true;
	};
	/**
	* 判断两个矩阵是否相等（两个矩阵尺寸相等且每个元素相同）
	*
	*
	*/
	var _isEqualTo=function(matrixA,matrixB){
		if(matrixA.length!=matrixB.length)return false;
		for(var h=0;h<matrixA.length;h++){
			if(matrixA[h].length!=matrixB[h].length)return false;
			for(var a=0;a<matrixA[h].length;a++){
				if(matrixA[h][a]!=matrixB[h][a])return false;
			}
		}
		return true;
	}
	/**
	* 判断矩阵A是否属于B，即(a&b)==a，又记作A∈B
	* 用于判断两个玩法的选项是否是关联关系，即选项A打出必然导致B打出
	*
	*/
	var _isMatrixABelongToB=function(matrixA,matrixB){
		return _isEqualTo(matrixA,_matrixAND(matrixA,matrixB));
	}
	/**
	* 生成关联关系路径方法
	* @param sets 数据集，用于查找关联关系的数据集，应是一个数组
	* @param checkRelationFunction 检查关联关系的方法，应能检查数据集里其中两个元素之间的关联关系，并返回boolean类似说明是否关联
	* @return pathList 根据关联关系生成的有向路径列表
	*/
	var _generalPathOfBelongRelation=function(sets,checkRelationFunction){
		/*
		var target=['a','b','c','d','e'];
		var checkBelongTo=function(a,b){
			var relation=[
				['a','b'],
				['a','c'],
				['b','c'],
				['c','a']
			];
			for(var i in relation){
				if(a==relation[i][0]&&b==relation[i][1])return true;
			}
			return false;
		}
		*/
		/*
		给出目标集合：
		 a b c d e
		已知关联关系 a>b, a>c, b>c, c>a
		
		答案：
			1. a>b>c
			2. a>c
			3. b>c>a
			4. c>a>b
			5. d
			6. e
		*/
		var findNext=function(targetKey,range,parent){
			var subRange=cloneObject(range);
			// 把搜索集合里当前元素剔除，避免重复搜索、以及形成回环
			subRange.splice(targetKey,1);
			for(var i in subRange){
				if(checkRelationFunction(range[targetKey],subRange[i])){
					//找到了下级
					var child={
						key: i,
						value: subRange[i],
						next: null,
						parent: null,
					}
					//现在的上级是否是已经有了下级，如果有，则复制一个新的上级（避免形成树结构，方便处理）
					if(parent.next!==null){
						var newParent={
							key: parent.key,
							value: parent.value,
							next: child,
							parent: parent.parent
						}
						var key=parent.parent.push(newParent)-1;
						child.parent=parent.parent[key];
					}
					else{// 现在的上级没有下级，直接把找到的下级合并上去
						parent.next=child;
						child.parent=parent;
					}
					//继续找下级的下级
					findNext(i,subRange,child);
				}
			}
		};
		var pathList=[];
		for(var i in sets){
			pathList.push({
				"key":i,
				"value":sets[i],
				"next":null,
				"parent":pathList
			});
			findNext(i,sets,pathList[pathList.length-1]);
		}
		return pathList;
		// console.log(pathList);
	}
	/**
	* 这个是生成关联路径函数的草稿
	*/
	var __generalPathOfBelongRelation_draft=function(){
		var target=['a','b','c','d','e'];
		var checkBelongTo=function(a,b){
			var relation=[
				['a','b'],
				['a','c'],
				['b','c'],
				['c','a']
			];
			for(var i in relation){
				if(a==relation[i][0]&&b==relation[i][1])return true;
			}
			return false;
		}
		/*
		给出目标集合：
		 a b c d e
		已知关联关系 a>b, a>c, b>c, c>a
		
		答案：
			1. a>b>c
			2. a>c
			3. b>c>a
			4. c>a>b
			5. d
			6. e
		*/
		var findNext=function(targetKey,range,parent){
			var subRange=cloneObject(range);
			// 把搜索集合里当前元素剔除，避免重复搜索、以及形成回环
			subRange.splice(targetKey,1);
			for(var i in subRange){
				if(checkBelongTo(range[targetKey],subRange[i])){
					//找到了下级
					var child={
						key: i,
						value: subRange[i],
						next: null,
						parent: null,
					}
					//现在的上级是否是已经有了下级，如果有，则复制一个新的上级（避免形成树结构，方便处理）
					if(parent.next!==null){
						var newParent={
							key: parent.key,
							value: parent.value,
							next: child,
							parent: parent.parent
						}
						var key=parent.parent.push(newParent)-1;
						child.parent=parent.parent[key];
					}
					else{// 现在的上级没有下级，直接把找到的下级合并上去
						parent.next=child;
						child.parent=parent;
					}
					//继续找下级的下级
					findNext(i,subRange,child);
				}
			}
		};
		var pathList=[];
		for(var i in target){
			pathList.push({
				"key":i,
				"value":target[i],
				"next":null,
				"parent":chain
			});
			findNext(i,target,pathList[pathList.length-1]);
		}
		console.log(pathList);
	}
	var _calculatePrizeRange=function(){
		// 生成每场比赛的玩法-选项笛卡尔矩阵，存起来，后面的互斥剪枝和关联检测都基于这个数据
		// 互斥检测并剪枝，在剪枝结果中找到每场比赛奖金最大的组合（赔率乘积最大）
		// 关联检测，找到所有关联关系，并找到每场比赛奖金最少的关联关系
		// 根据过关方式生成比赛组合
		// 分别把上面找到的每场比赛的一个奖金最大的组合、一个奖金最少的关联关系，分别代入比赛组合当中，计算每个比赛组合的奖金
		// 怎么计算每个比赛组合的奖金：将每场比赛的奖金最大组合相乘，得到这个比赛组合的最大奖金，将每场比赛京津最少的关联关系相乘，得到这个比赛组合的最少奖金
		// 找到最大奖金最大的比赛组合，即为最大奖金组合，其奖金为当前方案最大奖金
		// 找到最小奖金最少的比赛组合，即为最少奖金组合，其奖金为当前方案最少奖金
		if(order.orderObject._group_type_obj.length==0)return;

		// 生成玩法-选项笛卡尔矩阵存在_content_obj[i]._selection_catesian_matrix当中
		for(var matchItemIndex in order.orderObject._content_obj){
			// 生成按玩法分类的选项列表
			order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype={};
			for(var betContentItemIndex in order.orderObject._content_obj[matchItemIndex].betContent){
				var playtypeid=order.orderObject._content_obj[matchItemIndex].betContent[betContentItemIndex].playtypeid;
				if(!Array.isArray(order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype[playtypeid])){
					order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype[playtypeid]=[];
				}
				order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype[playtypeid].push(order.orderObject._content_obj[matchItemIndex].betContent[betContentItemIndex]);
			}
			// 生成玩法-选项笛卡尔积矩阵
			var selectionCartesianMatrixList=[];
			// 若总共有n种玩法，则需要生成n到1各个长度的笛卡尔积组合
			for(var i=Object.values(order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype).length;i>0;i--){
				// 根据”按玩法分类的选项列表“，生成不同长度组合，然后计算各个组合的笛卡尔积
				var combinResult=combination(Object.values(order.orderObject._content_obj[matchItemIndex]._selection_index_by_playtype),i);
				for(var j in combinResult){
					selectionCartesianMatrixList=selectionCartesianMatrixList.concat(cartesianProductOf(combinResult[j]));
				}
			}
			order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix=selectionCartesianMatrixList;
		};

		// 检测互斥，剪枝，结果存储到order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix_pruned
		// 剪枝结果中找到奖金(赔率)最大的组合，存储到_max_odds_selection的combination当中，另外把最大赔率的值存储到odds当中
		for(var matchItemIndex in order.orderObject._content_obj){
			var catesianMatrix=order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix;
			order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix_pruned=[];
			order.orderObject._content_obj[matchItemIndex]._relation_path=[];
			for(var i in catesianMatrix){
				// ******遍历玩法-选项笛卡尔矩阵，在这里找到互斥和关联关系，并分别处理******

				// 1. 找到互斥组合，并剪枝
				//遍历玩法-选项笛卡尔矩阵，找出互斥的选项组合，如果互斥则把当前i指定的组合剪枝（不加入新的剪枝结果数组）
				if(catesianMatrix[i].length<2){
					//如果只有一个玩法，就不存在玩法之间的互斥问题，直接可以加入到剪枝结果当中
					order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix_pruned[i]=catesianMatrix[i];
				}
				else{
					var combinList=combination(catesianMatrix[i],2);	//选项两两组合

					combinList.forEach(function(item){
						//遍历两两组合的结果
						//生成矩阵
						var matrixA=_generalScoreMatrix(item[0].playtypeid,{
							selection: item[0].selection,
							handicap: order.orderObject._content_obj[matchItemIndex].handicap
						});
						var matrixB=_generalScoreMatrix(item[1].playtypeid,{
							selection: item[1].selection,
							handicap: order.orderObject._content_obj[matchItemIndex].handicap
						});
						// 若两个矩阵不互斥（并集不为零矩阵）则加入到剪枝结果数组中
						if(!_isZeroMatrix(_matrixAND(matrixA,matrixB))){
							order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix_pruned[i]=catesianMatrix[i];
						}
					});
				}

				// 2. 找到全部关联路径
				// 找到当前玩法的选项组合下的关联路径
				var pathListInThisCatesian=_generalPathOfBelongRelation(catesianMatrix[i],function(selectionA,selectionB){
					var matrixA=_generalScoreMatrix(selectionA.playtypeid,{
						selection: selectionA.selection,
						handicap: order.orderObject._content_obj[matchItemIndex].handicap
					});
					var matrixB=_generalScoreMatrix(selectionB.playtypeid,{
						selection: selectionB.selection,
						handicap: order.orderObject._content_obj[matchItemIndex].handicap
					});
					return _isMatrixABelongToB(matrixA,matrixB);
				});
				// 把当前找到的关联路径合并到当前比赛的关联路径列表order.orderObject._content_obj[matchItemIndex]._relation_path中
				order.orderObject._content_obj[matchItemIndex]._relation_path=order.orderObject._content_obj[matchItemIndex]._relation_path.concat(pathListInThisCatesian);

			}

			// 剪枝结果中找到奖金(赔率)最大的组合，存储到_max_odds_selection的combination当中，另外把最大赔率的值存储到odds当中
			order.orderObject._content_obj[matchItemIndex]._max_odds_selection={
				combination: null,
				odds: 0
			};
			order.orderObject._content_obj[matchItemIndex]._selection_catesian_matrix_pruned.forEach(function(item){
				var oddsSum=item.reduce(function(sum,next){
					return sum+next.odds;
				},0);
				if(oddsSum>order.orderObject._content_obj[matchItemIndex]._max_odds_selection.odds){
					order.orderObject._content_obj[matchItemIndex]._max_odds_selection.odds=oddsSum;
					// order.orderObject._content_obj[matchItemIndex]._max_odds_selection.combination=item;
				}
			});

			// 遍历关联路径列表order.orderObject._content_obj[matchItemIndex]._relation_path，计算每个关联路径的奖金(赔率)，
			// 并找到本场比赛奖金最少的关联路径，存储到_min_odds_selection的path当中，另外把它的赔率值存储到odds当中
			order.orderObject._content_obj[matchItemIndex]._min_odds_selection={
				path: null,
				odds: null
			};
			order.orderObject._content_obj[matchItemIndex]._relation_path.forEach(function(item){
				//计算总赔率
				var oddsSum=item.value.odds;
				var next=item.next;
				while(!!next){
					oddsSum+=next.value.odds;
					next=next.next;
				}
				item.oddsSum=oddsSum;
				// 找到最少的值
				if(order.orderObject._content_obj[matchItemIndex]._min_odds_selection.odds===null ||
					oddsSum<order.orderObject._content_obj[matchItemIndex]._min_odds_selection.odds)
				{
					order.orderObject._content_obj[matchItemIndex]._min_odds_selection.odds=oddsSum;
					// order.orderObject._content_obj[matchItemIndex]._min_odds_selection.path=item;	// 存储路径会导致循环引用
					// 当存在循环引用时，使用JSON.stringify时会报错：Converting circular structure to JSON
				}

			});
			delete order.orderObject._content_obj[matchItemIndex]._relation_path;	// 保留路径会导致循环引用
		}

		// 3. 生成比赛组合，并计算全部组合的赔率乘积

		// 这个是按过关方式构造的选项矩阵列表
		var listOfMatchByParlay=[];
		var maxOdds=0;
		var minOdds=0;
		// 遍历全部过关方式，构造各个过关方式的比赛列表
		for(var i in order.orderObject._group_type_obj){
			// 只支持普通过关，不支持混合过关
			if(order.orderObject._group_type_obj[i].substr(-3)=='001'){
				// 取出过关数
				var countOfParlay=parseInt(order.orderObject._group_type_obj[i].substr(0,1));
				// 用排列算法按过关数构造选项列表
				var result=combination(order.orderObject._content_obj,countOfParlay);
				// 将构造出来的选项列表并入总列表中
				listOfMatchByParlay=listOfMatchByParlay.concat(result);
			}
		}
		for(var i in listOfMatchByParlay){
			listOfMatchByParlay[i]._maxOddsProduct=listOfMatchByParlay[i].reduce(function(product,next){
				return product*next._max_odds_selection.odds;
			},1);
			listOfMatchByParlay[i]._minOddsProduct=listOfMatchByParlay[i].reduce(function(product,next){
				return product*next._min_odds_selection.odds;
			},1);
			maxOdds+=listOfMatchByParlay[i]._maxOddsProduct;
			minOdds+=listOfMatchByParlay[i]._minOddsProduct;
		}
		// console.log(listOfMatchByParlay);
		// console.log('Max Payout: '+maxOdds*2+' , Min Payout: '+minOdds*2);
		order.orderObject.max_prize=(maxOdds*order.getMultiple()*2).toFixed(2);
		order.orderObject.min_prize=(minOdds*order.getMultiple()*2).toFixed(2);
		console.log('Prize range generated.')
	};
	order.choose=function(matchid,matchtime,matchkey,draw,handicap,playtype,selection,odds){
		var matchItemModel={
			matchid:matchid,
			matchtime:matchtime,
			draw:draw,
			matchkey:matchkey,
			handicap:handicap,
			guts:0,
			betContent:[],
			setBetContent: _setBetContentItem
		};
		var betContentModel={
			playtypeid:null,
			id:null,	// 兼容接口的历史遗留问题，接口通过id读取playtypeid，跟文档实际约定不一致
			selection:null,
			odds:null,
		};
		switch(playtype){
			case 'had':
				betContentModel.playtypeid=betContentModel.id=order.PLAYTYPEID.SPF; break;
			case 'hhad':
				betContentModel.playtypeid=betContentModel.id=order.PLAYTYPEID.RQSPF; break;
			default:
		}
		switch(selection){
			case 'homewin':
				betContentModel.selection=order.SELECTION.HOMEWIN; break;
			case 'draw':
				betContentModel.selection=order.SELECTION.DRAW; break;
			case 'awaywin':
				betContentModel.selection=order.SELECTION.AWAYWIN; break;
			default:
		}
		betContentModel.odds=odds;
		var matchItem=_getOrCreateMatchItem(matchItemModel);
		matchItem.setBetContent(betContentModel);
		_generalBasicData();
		return;
	};
	// 移除一个选项
	order.remove=function(matchid,playtype,selectionName){
		var matchItemKey=null;
		// 遍历找到比赛，如果没有找到就直接返回
		for(var index in order.orderObject._content_obj){
			if(matchid==order.orderObject._content_obj[index].matchid){
				matchItemKey = index;
			}
		}
		if(matchItemKey===null)return;
		// 找到了就继续找比赛里面的选项
		var betContentItemKey=null;
		// 要先格式化一下playtype和selection
		var playtypeid=null;
		var selection=null;
		switch(playtype){
			case 'had':
				playtypeid=order.PLAYTYPEID.SPF; break;
			case 'hhad':
				playtypeid=order.PLAYTYPEID.RQSPF; break;
			default:
				return;
		}
		switch(selectionName){
			case 'homewin':
				selection=order.SELECTION.HOMEWIN; break;
			case 'draw':
				selection=order.SELECTION.DRAW; break;
			case 'awaywin':
				selection=order.SELECTION.AWAYWIN; break;
			default:
		}
		// 遍历刚刚找到的matchItem，找到具体的投注选项，如果没有找到就直接返回
		for(var index in order.orderObject._content_obj[matchItemKey].betContent){
			if(playtypeid==order.orderObject._content_obj[matchItemKey].betContent[index].playtypeid
				&& selection==order.orderObject._content_obj[matchItemKey].betContent[index].selection)
			{
				betContentItemKey=index;
			}
		}
		if(betContentItemKey===null)return;
		// 找到了就删除，如果只剩下一下个选项，就把整个比赛删掉，否则就只把选项删掉
		if(order.orderObject._content_obj[matchItemKey].betContent.length>1){
			order.orderObject._content_obj[matchItemKey].betContent.splice(betContentItemKey,1);
		}
		else{
			order.orderObject._content_obj.splice(matchItemKey,1);
		}
		_generalBasicData();
	};
	order.clear=function(){
		order.orderObject._content_obj=[];
		_generalBasicData();
		_deleteOrderInLocalStorage();
	};
	order.submit=function(){
		_setDefaultParlay(); // 只有当过关方式为空时才会生成
		_saveOrderToLocalStorage();
		console.log(order.orderObject);
		return true;
	};
	order.load=function(){
		_loadOrderFromLocalStorage();
		// _generalStringProperty();
	}
	order.getCountOfMatch=function(){
		return order.orderObject._content_obj.length;
	};
	order.setMultiple=function(amount){
		if(amount < 1 || amount>order.setting.maxMultiple)return;
		order.orderObject.multiple=amount
		_generalBasicData();
		_saveOrderToLocalStorage();
		return order.orderObject.multiple;
	};
	order.getMultiple=function(){
		return order.orderObject.multiple;
	}
	order.addParlayType=function(parlaytype){
		if(parlaytype.substr(-3)!='001')return;
		var countOfParlay=parseInt(parlaytype.substr(0,1));
		if(countOfParlay>order.getCountOfMatch() || countOfParlay<2)return;
		var exist=false;
		for(var i in order.orderObject._group_type_obj){
			if(order.orderObject._group_type_obj[i]==parlaytype){
				exist=true;
			}
		}
		if(!exist){
			order.orderObject._group_type_obj.push(parlaytype);
		}
		_generalBasicData();
		// order.orderObject.group_type=order.orderObject._group_type_obj.join(';');
		return order.orderObject.group_type;
	};
	order.removeParlayType=function(parlaytype){
		for(var i in order.orderObject._group_type_obj){
			if(order.orderObject._group_type_obj[i]==parlaytype){
				order.orderObject._group_type_obj.splice(i,1);
			}
		}
		_generalBasicData();
		// order.orderObject.group_type=order.orderObject._group_type_obj.join(';');
		return order.orderObject.group_type;
	};
	order.getCountOfLines=function(){
		return order.orderObject.bet_num;
	};
	order.getTotalAmount=function(){
		return order.getCountOfLines()*order.getMultiple()*2;
	}
	order.getParlayList=function(){
		return order.orderObject._group_type_obj;
	}
	order.getPrizeRange=function(){
		if( order.orderObject.max_prize ===null || order.orderObject.min_prize===null){
			_calculatePrizeRange();
		}
		return {
			maxPrize: order.orderObject.max_prize,
			minPrize: order.orderObject.min_prize
		};
	}
	// 取得干净无私有变量的订单对象，用于向后端提交订单信息接口
	order.getClearOrderObject=function(){
		_saveOrderToLocalStorage();
		return _getClearObject(order.orderObject);
	}
	order.insertMatchInfo=function(matchDataIndexByDraw){
		var existEmpty=false;
		var getMatchInfoByMatchId=function(matchid){
			for(var drawItemKey in matchDataIndexByDraw){
				for(var matchItemKey in matchDataIndexByDraw[drawItemKey].data){
					if(matchDataIndexByDraw[drawItemKey].data[matchItemKey].match_id==matchid){
						return matchDataIndexByDraw[drawItemKey].data[matchItemKey];
					}
				}
			}
			return null;
		}
		for(var i in order.orderObject._content_obj){
			var matchInfo=getMatchInfoByMatchId(order.orderObject._content_obj[i].matchid);
			if(matchInfo!==null){
				order.orderObject._content_obj[i]._match_info=matchInfo;
			}
			else{
				existEmpty=true;
			}
		}
		return !existEmpty;
	}
	order.getEarlierCloseTime=function(){
		var earlierCloseTime=null;
		var earlierCloseTimeStr=null;
		for(var i in order.orderObject._content_obj){
			var matchtime=(new FootballDate(order.orderObject._content_obj[i]._match_info.matchtime,'yyyy-MM-dd hh:mm;ss')).getDateObject();

			if(earlierCloseTime===null
				|| matchtime<earlierCloseTime)
			{
				earlierCloseTime=matchtime;
				earlierCloseTimeStr=order.orderObject._content_obj[i]._match_info.matchtime;
			}
		}
		return earlierCloseTimeStr;
	}
	window.order=order;
})();
